package main;

import gate.IGateEx;
import gate.ServerPackage;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.management.RuntimeErrorException;

import org.jhotdraw.draw.Figure;

import senders.BroadCaster;
import sr.logger.Logger;
import util.ResponsePackage;

import child.ChildServer;
import client.remote.ClientReceiver;

import master.MasterInterface;

public class Server extends UnicastRemoteObject implements MasterInterface {
	
	public Server() throws RemoteException
	{
		this.gateComm = GateComm.getComm();
	}
	GateComm gateComm;
	Logger logger = Logger.getLogger(Server.class);
	private Map<Long,ClientReceiver> clients = new HashMap();
	BroadCaster broadcaster = new BroadCaster(this);
	Map<ClientReceiver,Integer> errors = new TreeMap<ClientReceiver, Integer>();
	long userIdCounter = 0;
	final int MAX_ERROR_COUNT = 5;
	private int curentRoomCounter = 0;  
	@Override
	public void addChatMessage(String msg,Long tick) throws RemoteException 
	{
		logger.log(tick,"addChatMessage");
		broadcaster.bcMessage(msg);
		System.out.println("Got message");
	}
	private long getNextId() { return ++userIdCounter; }

	@Override
	public ResponsePackage<Long> register(ClientReceiver clientReceiver)
			throws RemoteException {
		long tick = logger.log("register");
		long userId = registerClient(clientReceiver);
		
		
		gateComm.addTask(GateTaskFactory.createRegisterTask(userId,clientReceiver));
		
		return new ResponsePackage<Long>(userId,tick);
	}

	private synchronized long  registerClient(ClientReceiver clientReceiver) {
		long userId = getNextId();
		clients.put(userId, clientReceiver);
		return userId;
	}

	@Override
	public synchronized void unregister(long clientId,Long tick) throws RemoteException 
	{
		
		logger.log(tick,"unregister");
		ClientReceiver client = clients.get(clientId);
		clients.remove(clientId);
		broadcaster.removeClient(client);
		gateComm.addTask(GateTaskFactory.createUnregisterTask(clientId));
		
	}
	@Override
	public void onStartButton(long clientId,Long tick) throws RemoteException 
	{
		
		logger.log(tick,"onStartButton");
		ClientReceiver client = clients.get(clientId);
		broadcaster.onGameJoinRequest(client);
	}
	public synchronized ArrayList<ClientReceiver> getClients()
	{
		ArrayList<ClientReceiver> lclients = new ArrayList<ClientReceiver>();
		for(Long id : clients.keySet())
			lclients.add(clients.get(id));
		
		return lclients;
	}
	public Long getIdByReceiver(ClientReceiver client)
	{
		for(Long key : clients.keySet())
		{
			if(clients.get(key) == client)
				return key;
		}
		return -1l;

	}
	public void reportError(ClientReceiver client)
	{
		Integer errorCount = errors.get(client);
		errors.put(client, ++errorCount);
		if(errorCount > MAX_ERROR_COUNT)
		{
			errors.remove(client);
			try
			{
				Long id = getIdByReceiver(client);
				if(id == -1)
					return;
				unregister(getIdByReceiver(client),logger.log("report error"));
			} catch (RemoteException e)
			{
				e.printStackTrace();
			}
		}
	}
	@Override
	public void statusCheck(Long tick) throws RemoteException
	{
		logger.log(tick,"statusCheck");
		
	}
	@Override
	public void build(ServerPackage servPackage,Long remoteTick)
	{
		
		logger.log(remoteTick, "build");
		ServerPackage sp = servPackage;
		userIdCounter = sp.getClientCounter();
		clients = new HashMap<Long, ClientReceiver>(sp.getClients());
		System.err.println("no clients" + clients.size());
		ArrayList<Long> clientIds = new ArrayList<Long>();
		this.curentRoomCounter = sp.getRoomCounter();
		Long tick = logger.log("Build","sending info about change server");
		for(Integer key : sp.getRooms().keySet())
		{
			clientIds = sp.getRooms().get(key);
			ArrayList<ClientReceiver> clientsInRoom = new ArrayList<ClientReceiver>();
			for(Long id : clientIds)
			{
				ClientReceiver client = clients.get(id);
				clientsInRoom.add(client);
				
			}
			try
			{
				ChildServer childServer = new ChildServer(clientsInRoom,this,key);
				
				for(ClientReceiver client : clientsInRoom)
				{
					
					client.changeServer(childServer,tick);
				}
			} catch (RemoteException e)
			{
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	public int getCurrentRoomCounter()
	{
		return ++curentRoomCounter ;
		
	}
}
